package com.cndw.kungfu.model.pve;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.cndw.kungfu.config.ConstantsLog;
import com.cndw.kungfu.config.ConstantsModel;
import com.cndw.kungfu.config.ConstantsRadio;
import com.cndw.kungfu.domain.Monster;
import com.cndw.kungfu.domain.Player;
import com.cndw.kungfu.ext.LanguageLib;
import com.cndw.kungfu.ext.LogUtil;
import com.cndw.kungfu.ext.TimeProcesser;
import com.cndw.kungfu.model.Context;
import com.cndw.kungfu.model.battle.FighterMonster;
import com.cndw.kungfu.model.sys.ChatMain;
import com.cndw.kungfu.model.sys.LogServer;
import com.cndw.kungfu.vo.EventNotice;
import com.cndw.kungfu.vo.battlevo.FighterAiVO;
import com.cndw.kungfu.vo.battlevo.PlayerDamVO;

/**
 * 襄阳保卫战
 * 
 * @author fantadust [9677889@qq.com]
 * @date 2012-6-24 上午11:39:26
 */
public class CityDefensesBattle {

	/**
	 * 开始时间
	 */
	private static final int startTime = 22 * 3600;
	/**
	 * 结束时间
	 */
	private static final int endTime = 22 * 3600 + 1800;
	/**
	 * 准备时间
	 */
	public static final int readyTime = 180;
	/**
	 * 每一波怪物存活时间
	 */
	public static final int monsterLifeTime = 150;
	/**
	 * 缓冲时间
	 */
	public static final int buffTime = 12;
	/**
	 * 场景id
	 */
	public static final int sceneId = 66004;

	private static final int[][] monsterIds = { { 5001, 5001, 5001, 5001, 5002 }, { 5003, 5003, 5003, 5003, 5004 }, { 5005, 5005, 5005, 5005, 5006 },
			{ 5007, 5007, 5007, 5007, 5008 }, { 5009, 5009, 5009, 5009, 5010 }, { 5011, 5011, 5011, 5011, 5012 }, { 5013, 5013, 5013, 5013, 5014 },
			{ 5015, 5015, 5015, 5015, 5016 }, { 5017, 5017, 5017, 5017, 5018 }, { 5019, 5019, 5019, 5019, 5020 } };

	private static final int[][] monsterXY = { { 2800, 385 }, { 2800, 505 }, { 2900, 325 }, { 2900, 565 }, { 2950, 445 } };

	private static final int[][] awardsConfig = { { 5020508, 1598887, 69096 }, { 6526660, 2078554, 89825 }, { 8484658, 2702120, 116772 },
		{ 11030055, 3512756, 151804 }, { 14339071, 4566583, 197345 }, { 18640792, 5936557, 256549 }, { 24233029, 7717525, 333514 },
		{ 31502937, 10032782, 433568 }, { 40953818, 13042617, 563639 }, { 53239963, 16955402, 732731 } };
	/**
	 * boss加血金币
	 */
	public static final int bossHpGold = 80;
	/**
	 * boss最大加血次数
	 */
	public static final int bossHpAddMax = 100;
	/**
	 * 复活一次
	 */
	public static final int reviveGold = 8;

	private static int currentStartTime = 0;

	private static final ConcurrentHashMap<Long, CityBattlePlayer> battlePlayerMap = new ConcurrentHashMap<Long, CityBattlePlayer>();
	
	private static final ConcurrentHashMap<Long, FighterMonsterAi> monstersMap = new ConcurrentHashMap<Long, FighterMonsterAi>();

	private static final ConcurrentHashMap<Integer, Long> akPlayerMap = new ConcurrentHashMap<Integer, Long>();
	/**
	 * boss血量
	 */
	private static volatile int bossHp = 0;
	/**
	 * 轮次
	 */
	private static volatile int step = 0;
	/**
	 * 0.无.1 刷怪了.2怪物跑掉了,3等待刷怪
	 */
	private static volatile int state = 0;
	/**
	 * 加血的次数
	 */
	private static volatile int bossHpAddTimes = 0;

	private static int monsterHpAll = 0;

	public static int monsterRefreshTime = 0;

	private static boolean signEnd = false;
	
	private static boolean signDoing = false;

	private static int lastOrderDam = 0;

	private static int clacStepAward = 0;

	private static ScheduledFuture<?> currentTask;

	private static int battleCost = 0;
	
	private static int roundAchive = 0;

	public static void runBoss() {
		int morningTime = TimeProcesser.getMorningTime();
		int currentTime = TimeProcesser.getUnixTime();
		currentStartTime = morningTime + startTime;
		if (currentTime >= morningTime + endTime) {
			currentStartTime += 86400;
		}
		Context.getTimerServer().scheduleAtFixedRate(new Runnable() {

			@Override
			public void run() {
				try {
					init();
					LogUtil.getSystem().debug("citydefensesbattle init");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}, currentStartTime - currentTime, 86400);
		LogUtil.getSystem().debug("citydefensesbattle start lelay:" + (currentStartTime - currentTime));
	}

	private static void init() {
		currentStartTime = TimeProcesser.getMorningTime() + startTime;
		monsterRefreshTime = currentStartTime + readyTime;
		reset();// 清理历史数据
		signDoing = true;
		addEvent();
	}

	private static void reset() {
		battlePlayerMap.clear();
		akPlayerMap.clear();
		monstersMap.clear();
		state = 0;
		step = 0;
		bossHp = 100;
		bossHpAddTimes = 0;
		monsterHpAll = 0;
		monsterRefreshTime = 0;
		signEnd = false;
		lastOrderDam = 0;
		clacStepAward = 0;
		if (currentTask != null) {
			currentTask.cancel(false);
		}
	}

	/**
	 * 刷新出怪物
	 */
	private static synchronized void monsterRefresh() {
		if (isActivityOver()) {
			over();
			return;
		}
		state = 1;
		monsterRefreshTime = TimeProcesser.getUnixTime();
		roundAchive = 0;
		try {

			int[] ids = monsterIds[step];
			for (int i = 0; i < ids.length; i++) {
				int monsterId = ids[i];
				Monster monster = Context.getUndercityServer().getMonster(monsterId);
				if (monster == null) {
					continue;
				}
				FighterMonster fighter = monster.fighter();
				FighterMonsterAi ai = new FighterMonsterAi(monsterId, sceneId, fighter);

				ai.setX(monsterXY[i][0]);
				ai.setY(monsterXY[i][1]);

				monsterHpAll += fighter.getMaxHp();

				monstersMap.put(ai.getUniqueId(), ai);

			}

			Collection<FighterMonsterAi> monsterAis = CityDefensesBattle.getFighters();
			List<FighterAiVO> currentDeploys = new ArrayList<FighterAiVO>(monsterAis.size());
			for (FighterMonsterAi e : monsterAis) {
				currentDeploys.add(e.toVO());
			}

			EventNotice eventNotice = new EventNotice(ConstantsRadio.cityBattle, ConstantsRadio.cityBattleRefresh);
			eventNotice.comitData(currentDeploys);
			eventNotice.put("bossHp", bossHp);
			eventNotice.broadcastAllScene(sceneId);
			step++;

			ChatMain.systemMessage(LanguageLib.get("pve.city.stepstart", step));

			LogUtil.getSystem().debug("CityDefensesBattle refresh " + step);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private static synchronized void monsterClear() {
		state = 2;
		if (monstersMap.isEmpty()) {
			return;
		}
		try {
			for (FighterMonsterAi ai : monstersMap.values()) {
				bossHpAlter(-20, false);
				EventNotice eventNotice = new EventNotice(ConstantsRadio.cityBattle, ConstantsRadio.cityBattleLoss);
				eventNotice.put("uniqueId", ai.getUniqueId());
				eventNotice.put("bossHp", bossHp);
				eventNotice.broadcastAllScene(sceneId);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		monstersMap.clear();
		clacAward();// 结算奖励
		if (isActivityOver()) {
			over();
		}
		LogUtil.getSystem().debug("CityDefensesBattle clear  " + step + " hp:" + bossHp);
	}

	private static synchronized void clacAward() {
		if (step <= clacStepAward) {
			return;
		}
		if (bossHp > 0) {
			roundAchive += ConstantsModel.cbRoundPassAward[step - 1];
		}
		clacStepAward = step;
		int awardStep = step - 1;
		if (awardStep >= 0 && awardStep < awardsConfig.length) {
			int expAll = awardsConfig[awardStep][0];
			int assetAll = awardsConfig[awardStep][1];
			int expAck = awardsConfig[awardStep][2];

			EventNotice eventNotice = new EventNotice(ConstantsRadio.cityBattle, ConstantsRadio.cityBattleAward);
			eventNotice.put("awardStep", clacStepAward);
			long akPlayerId = 0;
			if (akPlayerMap.containsKey(clacStepAward)) {
				akPlayerId = akPlayerMap.get(clacStepAward);
				Player player = Context.getPlayerServer().getByPlayerId(akPlayerId);
				if (player != null) {
					eventNotice.put("akId", akPlayerId);
					eventNotice.put("akName", player.getPlayerName());
					eventNotice.put("akAsset", expAck);
					ChatMain.systemMessageDelay(LanguageLib.get("pve.city.stepsuc", player.getPlayerName(), step), battleCost);
				}

			} else {
				ChatMain.systemMessageDelay(LanguageLib.get("pve.city.steperr"), 5);
			}
			
			for (CityBattlePlayer e : battlePlayerMap.values()) {
				if (e.getDam() <= 0) {
					continue;
				}
				
				Player player = Context.getPlayerServer().getByPlayerId(e.getPlayerId());
				if (player == null || player.getSceneId() != sceneId || !player.isOnline()) {
					continue;
				}
				float coff = 1f * e.getDam() / monsterHpAll;
				coff = Math.min(0.010f, Math.max(coff, 0.001f));

				int exp = (int) (expAll * coff);
				int asset = (int) (assetAll * coff);
				int akAsset = akPlayerId == e.getPlayerId() ? expAck : 0;
				int achive = 0;
				if (bossHp > 0) {
					achive = (int)(coff  * roundAchive);
					player.getDataInfo().alterAchive(achive);
					player.getDataInfo().commitSync();
					eventNotice.put("getAchive", achive);
				}
				
				player.alterExp(exp);
				player.alterAsset(asset + akAsset);
				player.commitSync();

				eventNotice.put("gotExp", exp);
				eventNotice.put("gotAsset", asset);

				eventNotice.broadcast(e.getPlayerId());
				LogServer.recordLog(player, ConstantsLog.battle, 40305, exp, asset, akAsset, clacStepAward, achive);
			}
		}
	}

	private static synchronized void over() {

		LogUtil.getSystem().debug("CityDefensesBattle over");

		end();
	}

	private static synchronized void end() {
		if (currentTask != null) {
			currentTask.cancel(false);
		}
		if (signEnd) {
			return;
		}
		signEnd = true;
		signDoing = false;
		LogUtil.getSystem().debug("CityDefensesBattle end");

		EventNotice eventNotice = new EventNotice(ConstantsRadio.cityBattle, ConstantsRadio.cityBattleEnd);
		List<PlayerDamVO> vos = orderDam();
		List<Object> headNames = new ArrayList<Object>();
		int orderId = 0;
		for (PlayerDamVO akVo : vos) {
			orderId++;
			headNames.add(new Object[] { akVo.getPd(), akVo.getPn(), akVo.getDam(), orderId });
			if (orderId >= 3) {
				break;
			}
		}
		int winStep = step - 1;
		eventNotice.put("winStep", winStep);
		eventNotice.put("orderNames", headNames);
		try {
			if (akPlayerMap.contains(monsterIds.length)) {
				long akPlayerId = akPlayerMap.get(monsterIds.length);
				Player player = Context.getPlayerServer().getByPlayerId(akPlayerId);
				if (player != null) {
					eventNotice.put("akId", akPlayerId);
					eventNotice.put("akName", player.getPlayerName());
					eventNotice.put("akAsset", awardsConfig[monsterIds.length][2]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		ChatMain.systemMessageDelay(LanguageLib.get(bossHp > 0 ? "pve.city.suc" : "pve.city.faild"), battleCost);

		eventNotice.broadCastAllOnLine();// 广播所有人

	}

	private static synchronized void addEvent() {
		try {
			if (signEnd) {// 已经结束了
				LogUtil.getMain().debug("CityDefensesBattle event over  ");
				return;
			}
			int delay = readyTime;
			if (state == 0) {
				delay = readyTime;// 第一次进来.等待准备时间
			} else if (state == 1) {
				delay = monsterLifeTime;// 等待怪物行走
			} else if (state == 2) {
				delay = buffTime;
			}
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					try {

						int curretState = state;
						if (curretState == 0) {
							monsterRefresh();
						} else if (curretState == 1) {
							monsterClear();
						} else if (curretState == 2) {
							monsterRefresh();
						}
						addEvent();// 再次增加事件
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			};

			currentTask = Context.getTimerServer().schedule(runnable, delay * 1000, TimeUnit.MILLISECONDS);
			LogUtil.getSystem().debug("CityDefensesBattle lelay :" + delay);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void removeFighterMonsterAi(long id, int battleCost) {
		FighterMonsterAi ai = monstersMap.remove(id);
		if (ai == null) {
			return;
		}
		if (ai.getFighter().getSourceObject().getBoss() == 5) {
			roundAchive += ConstantsModel.cbBossAward[step - 1];
		} else {
			roundAchive += ConstantsModel.cbMonstorAward[step - 1];
		}
		
		CityDefensesBattle.battleCost = battleCost;
		if (monstersMap.isEmpty()) {// 怪物打完
			
			clacAward();
			if (isActivityOver()) {// 怪物全部杀死了
				end();
			}
		}
	}

	private static boolean isActivityOver() {
		return bossHp <= 0 || step >= monsterIds.length;
	}

	public static synchronized void bossHpAlter(int alter, boolean addTimes) {
		bossHp += alter;
		bossHp = bossHp < 0 ? 0 : bossHp;
		if (addTimes) {
			bossHpAddTimes++;
		}
	}

	public static int getBossHpAddTimes() {
		return bossHpAddTimes;
	}

	public static Collection<FighterMonsterAi> getFighters() {
		return monstersMap.values();
	}

	public static FighterMonsterAi getFighterAi(long id) {
		return monstersMap.get(id);
	}

	public static boolean isSignEnd() {
		return signEnd;
	}

	public static int getBossHp() {
		return bossHp;
	}

	public static int getBuffAdd(long playerId) {
		if (battlePlayerMap.containsKey(playerId)) {
			return battlePlayerMap.get(playerId).getBuff();
		}
		return 0;
	}

	public static int getCurrentStartTime() {
		if (signEnd) {
			currentStartTime += 86400;
		}
		return currentStartTime;
	}

	public static void playerDamAdd(long playerId, int dam) {
		playerInit(playerId);
		battlePlayerMap.get(playerId).alterDam(dam);

	}

	public static void playerBuffSet(long playerId, int buff) {
		if (buff <= 0) {
			return;
		}
		playerInit(playerId);
		battlePlayerMap.get(playerId).setBuff(buff);
	}

	public static void playerInit(long playerId) {
		if (!battlePlayerMap.containsKey(playerId)) {
			CityBattlePlayer cbp = new CityBattlePlayer();
			cbp.setPlayerId(playerId);
			battlePlayerMap.putIfAbsent(playerId, cbp);
		}
	}

	public static CityBattlePlayer playerGet(long playerId) {
		if (!battlePlayerMap.containsKey(playerId)) {
			return null;
		}
		return battlePlayerMap.get(playerId);
	}

	public static void akPlayerSet(long playerId) {
		akPlayerMap.putIfAbsent(step, playerId);
	}
	
	public static boolean isOderTop(int dam) {
		return lastOrderDam <= dam;
	}

	public static int getMonsterHpAll() {
		return monsterHpAll;
	}

	public static boolean isSignDoing() {
		return signDoing;
	}

	public static List<PlayerDamVO> orderDam() {

		Set<CityBattlePlayer> orderSet = new TreeSet<CityBattlePlayer>(battlePlayerMap.values());
		List<PlayerDamVO> damVOs = new ArrayList<PlayerDamVO>();
		int orderId = 0;
		for (CityBattlePlayer e : orderSet) {
			orderId++;
			Player player = Context.getPlayerServer().getByPlayerId(e.getPlayerId());

			PlayerDamVO ve = new PlayerDamVO();
			ve.setPd(e.getPlayerId());
			ve.setPn(player.getPlayerName());
			ve.setDam(e.getDam());
			ve.setO(orderId);
			damVOs.add(ve);

			if (orderId == 10) {
				lastOrderDam = e.getDam();
			}
			if (orderId >= 10) {
				break;
			}
		}
		return damVOs;

	}

}
